package server

import (
	"context"
	"errors"
	"fmt"
	"github.com/go-playground/validator/v10"
	"mime"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
	"wx-uniapp-go/routers"
	"wx-uniapp-go/runtime"
	"wx-uniapp-go/third_party/aeslib"
	"wx-uniapp-go/third_party/cdslog/writer"
	"wx-uniapp-go/third_party/constdata"
	"wx-uniapp-go/third_party/oss"
	"wx-uniapp-go/third_party/validatorv10"
	"wx-uniapp-go/third_party/wechat"
	"xorm.io/xorm/contexts"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	zhTranslations "github.com/go-playground/validator/v10/translations/zh"
	"github.com/spf13/viper"
	"wx-uniapp-go/third_party/cdslog"
	"wx-uniapp-go/third_party/mysql"
	"wx-uniapp-go/third_party/rediscli"
)

func Init(configPaths ...string) {
	// mime类型
	_ = mime.AddExtensionType(".mp4", "video/mp4")
	_ = mime.AddExtensionType(".webm", "video/webm")
	_ = mime.AddExtensionType(".mov", "video/quicktime")

	initConfig(configPaths...)
	//initTracer()
	runtime.RunMode = viper.GetString("app.http.mode")
	initLogger()
	//initReqRspLogger()
	initMysql()
	initRedis()

	//业务
	initOSS()
	//initOBS()
	initWechat()

	initTools()

}

// Run 启用webserver
func Run() {
	// 执行模式
	gin.SetMode(ginMode())
	engine := gin.New()
	//gin.Default()
	routers.SetEngine(engine)
	routers.Init()
	// 参数校验翻译
	bindValidator()
	server := &http.Server{
		Addr:    ginAddr(),
		Handler: engine,
	}
	go func() {
		if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			cdslog.Error("Application start failed: " + err.Error())
			panic(err)
		}
	}()
	cdslog.Info(fmt.Sprintf("Application start success on Ports:[%d]", viper.GetInt("app.http.port")))
	// 优雅关闭
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
	<-quit
	cdslog.Info("Shutdown server ...")
	ctx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancelFunc()
	if err := server.Shutdown(ctx); err != nil {
		cdslog.Error(fmt.Sprintf("Server shutdown failure, %s", err.Error()))
		panic(err)
	}
	time.Sleep(5 * time.Second) // 等待部分资源释放
	cdslog.Info("Server exiting ...")
}

func bindValidator() {
	validatorv10.InitUniversal()
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		err := zhTranslations.RegisterDefaultTranslations(v, validatorv10.ValiTrans)
		if err != nil {
			cdslog.Error(err.Error())
		}
	}
}

func ginMode() string {
	cMode := viper.GetString("app.http.mode")
	if cMode == runtime.PROD {
		cMode = gin.ReleaseMode
	} else {
		cMode = gin.DebugMode
	}
	return cMode
}

func ginAddr() string {
	viper.SetDefault("app.http.addr", "0.0.0.0")
	viper.SetDefault("app.http.port", 8080)
	addr := viper.GetString("app.http.host")
	port := viper.GetInt("app.http.port")
	return fmt.Sprintf("%s:%d", addr, port)
}

// init
func initConfig(configPaths ...string) {
	configPath := ""
	if len(configPaths) > 0 {
		configPath = configPaths[0]
		viper.AddConfigPath(configPath)
	}
	viper.SetConfigName("application") // name of config file (without extension)
	viper.SetConfigType("yml")         // REQUIRED if the config file does not have the extension in the name
	viper.AddConfigPath("./conf/")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}

// 初始化新年工作流任务池
//func initNewYearRedisTaskPool() {
//	taskpool.InitNewYearRedisTaskPool(func(NewYearRedisTaskPool *taskpool.RedisTaskPool) {
//		// 初始化回调方法
//		NewYearRedisTaskPool.Handle(func(task string) error {
//			var input newyear_worker.GreetingWorkflowArg
//			_ = json.Unmarshal([]byte(task), &input)
//
//			co := client.Options{
//				HostPort:  viper.GetString("temporal.host_port"),
//				Namespace: "new_year_2024",
//			}
//			c, err := client.Dial(co)
//
//			if err != nil {
//				cdslog.Error(err.Error())
//				return err
//			}
//
//			defer c.Close()
//
//			options := client.StartWorkflowOptions{
//				ID:                 fmt.Sprintf("newyear2024-%s", input.TaskId),
//				TaskQueue:          cmd_worker.HappyNewYear2024TaskQueue,
//				WorkflowRunTimeout: time.Hour * 10,
//			}
//			_, err = c.ExecuteWorkflow(context.Background(), options, "NewYear2024GreetingWorkflow", input)
//			if err != nil {
//				cdslog.Error(err.Error())
//				return err
//			}
//			return nil
//		})
//	})
//}

// 初始化公共日志组件
func initLogger() {
	var err error
	if runtime.RunMode == runtime.DEV {
		//err = cdslog.InitLogger("", "info")
		err = cdslog.InitDefaultLogger(
			cdslog.TYPESTDOUT,
			cdslog.NewConfig(
				//cdslog.WithTraceIdFunc(pluginstools.NewOtelTraceIdFunc()),
				cdslog.WithTraceIdFunc(cdslog.NewTraceIdFunc()),
			),
		)
	} else {
		//else if runtime.RunMode == runtime.PROD {
		//	// 线上环境，华为云，使用文件收集的方式进行提交
		//	logCfg := cdslog.NewConfig(cdslog.WithFilePath("/tmp/process.log"))
		//	err = cdslog.InitDefaultLogger(cdslog.TYPEFILE, logCfg)
		//}
		akid := viper.GetString("aliyun.sls.akid")
		aksecret := viper.GetString("aliyun.sls.aksecret")
		project := viper.GetString("aliyun.sls.project")
		endpoint := viper.GetString("aliyun.sls.endpoint")
		logstore := viper.GetString("aliyun.sls.logstore")
		//driverCfg := fmt.Sprintf(`{"endpoint":"%s","access_key_id":"%s","access_key_secret":"%s","default_project":"%s","default_logstore":"%s"}`, endpoint, akid, aksecret, project, logstore)
		//err = cdslog.InitLogger("logs/custom.log", "info")
		//err = cdslog.InitLogger(driverCfg, "info", "aliyunsls")
		logCfg := cdslog.NewConfig(
			cdslog.WithAliyunSLSConfig(&writer.SlsConfig{
				Endpoint:        endpoint,
				DefaultProject:  project,
				DefaultLogstore: logstore,
				AccessKeyID:     akid,
				AccessKeySecret: aksecret,
			}),
			cdslog.WithTraceIdFunc(cdslog.NewTraceIdFunc()),
		)
		err = cdslog.InitDefaultLogger(
			cdslog.TYPEALIYUNSLS,
			logCfg,
		)
	}
	if err != nil {
		panic(err)
	}
}

// 初始化输入输出中间件，和公共日志组件分开的原因一个性能方面，二是日志格式方式的考量，也不排除将来合并
//func initReqRspLogger() {
//	akid := viper.GetString("aliyun.sls.akid")
//	aksecret := viper.GetString("aliyun.sls.aksecret")
//	project := viper.GetString("aliyun.sls.project")
//	endpoint := viper.GetString("aliyun.sls.endpoint")
//	logstore := viper.GetString("aliyun.sls.logstore")
//	driverCfg := fmt.Sprintf(`{"endpoint":"%s","access_key_id":"%s","access_key_secret":"%s","project":"%s","logstore":"%s"}`, endpoint, akid, aksecret, project, logstore)
//	customlog.InitLogIns("aliyunsls", driverCfg)
//	//driverCfg := fmt.Sprintf(`{"log_path":"%s"}`, "logs/request.log")
//	//customlog.InitLogIns("file", driverCfg)
//}

// 操作单mysql库的简单用法
func initMysql() {
	dsn := viper.GetString("mysql.default.dsn")
	debug := viper.GetBool("mysql.default.debug")
	maxidle := viper.GetInt("mysql.default.pool.idle")
	maxopen := viper.GetInt("mysql.default.pool.active")
	logHook := make([]contexts.Hook, 0)
	logHook = append(logHook, &mysql.CdsMysqlHook{
		DBName:   "",
		DBUser:   "",
		LogLevel: constdata.LEVEL_ALL,
	})
	opt := mysql.MysqlOptions{
		Debug:       debug,
		Dns:         dsn, //"root:123@tcp(127.0.0.1:3306)/captcha?charset=utf8mb4"
		MaxIdleConn: maxidle,
		MaxOpenConn: maxopen,
		LogHook:     logHook,
	}
	err := mysql.InitDefaultMysql(opt)
	if err != nil {
		panic(err)
	}
}

// 操作单Redis库的简单用法
func initRedis() {
	host := viper.GetString("redis.default.host")
	port := viper.GetInt("redis.default.port")
	passwd := viper.GetString("redis.default.auth")
	db := viper.GetInt("redis.default.db")
	poolsize := viper.GetInt("redis.default.pool.idle")
	minIdleConns := viper.GetInt("redis.default.min_idle")
	maxRetries := viper.GetInt("redis.default.max_retries")
	enableTrace := viper.GetBool("redis.default.enable_trace")
	err := rediscli.InitDefaultRedis(&rediscli.RedisConfig{
		Host:         fmt.Sprintf("%s:%d", host, port),
		Password:     passwd,
		DB:           db,
		PoolSize:     poolsize,
		MinIdleConns: minIdleConns,
		MaxRetries:   maxRetries,
		EnableTrace:  enableTrace,
		SlowLogTime:  100 * time.Millisecond,
	})

	if err != nil {
		panic(err)
	}
}

func initOSS() {
	// 避免导致初始化崩溃
	if viper.Sub("aliyun.oss") != nil {
		oss.CreateBean()
	}
}

// initWechat 初始化微信配置
func initWechat() {
	wechat.InitOfficeAccountConfigConfig(viper.GetString("wechat.token"), viper.GetString("wechat.appid"),
		viper.GetString("wechat.appsecret"), viper.GetString("wechat.encode_aeskey"))
	wechat.InitMPConfig(viper.GetString("wechat.xiaoda.appid"), viper.GetString("wechat.xiaoda.appsecret"),
		viper.GetString("wechat.xiaoda.creation_success_tmpl_id"), viper.GetString("wechat.xiaoda.creation_fail_tmpl_id"))
	//wechat.InitMPConfig("wx492ff80a143e39aa", "fc1ab9e74e0ed9a2f1026534c5fcab5d",
	//	"nv8PQZU9dQyLLFsuQRpw90o1hDoRrr9RLdj-KxFy49U", "wyriMOjT9nRJZLTDRdX0aqNzKFoo7ccLHCc4IDTpuu0")
	//wechat.InitMPCJConfig("wxe70f2c7cfc16eeb8", "73bc2a67e4353425ab0e2c70795005ff",
	//	"RQwIiJ2nYdwMA5NT9KRWsrsCKyKtpyc_PDZf6JK1Mf8", "NZ2BAt3V1ymU_4n5nCCZw9-maAmvNE4WVx5W9wq9LxY")
}

func initTools() {
	//初始化aes工具
	key := viper.GetString("encrypt.aes.key")
	iv := viper.GetString("encrypt.aes.iv")
	fmt.Println(key, iv)
	err := aeslib.InitAesInstanceHex(key, iv)
	if err != nil {
		panic(err)
	}
}
